package com.vq3.digitalizationsoftwareintegrates.Servlet.WebSocket;

import com.vq3.digitalizationsoftwareintegrates.Entity.Enum.MessageType;
import com.vq3.digitalizationsoftwareintegrates.Entity.Spot_Check.MongoDBEntity.MongoDB_S_C_SaveSCDailyContextEntity;
import com.vq3.digitalizationsoftwareintegrates.Entity.Spot_Check.MongoDBEntity.MongoDB_S_C_SysAuthAuditMessageEntity;
import com.vq3.digitalizationsoftwareintegrates.Entity.Spot_Check.MongoDBEntity.MongoDB_S_C_WebSocketMessageEntity;
import com.vq3.digitalizationsoftwareintegrates.Entity.Spot_Check.MongoDBEntity.MongoDB_S_C_WebSocketSendMessageEntity;
import com.vq3.digitalizationsoftwareintegrates.Entity.Spot_Check.S_C_PointEntity;
import com.vq3.digitalizationsoftwareintegrates.Entity.User.*;
import com.vq3.digitalizationsoftwareintegrates.MongoDB.Spot_Check.MongoDB_S_C_SaveDailyContextDao;
import com.vq3.digitalizationsoftwareintegrates.Service.Spot_Check.Spot_Check_FusionService;
import com.vq3.digitalizationsoftwareintegrates.Service.MessageCenter.MessageCenterService;
import com.vq3.digitalizationsoftwareintegrates.Service.User.UserFusionService;
import com.vq3.digitalizationsoftwareintegrates.Service.User.UserLoginService;
import com.vq3.digitalizationsoftwareintegrates.Utils.DateUtils.GetServerDate;
import com.vq3.digitalizationsoftwareintegrates.Utils.ImageUtil.CalculationIsType;
import com.vq3.digitalizationsoftwareintegrates.Utils.PackagedDataUtil.ServerEncoder;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.net.http.WebSocket;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author y.h
 * this{pageCode} is username
 * */

@ServerEndpoint(value = "/websocket/{pageCode}",encoders = {ServerEncoder.class})
@Component
public class WebSocketServer {

    private static ApplicationContext applicationContext;

    public static void setApplicationContext(ApplicationContext context) {
        applicationContext = context;
    }




    private static final String loggerName = WebSocket.class.getName();
    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话，可以使用Map来存放，其中Key可以为用户标识
    public static Map<String, List<Session>> electricSocketMap = new ConcurrentHashMap<String, List<Session>>();




    /**
     * 连接建立成功调用的方法
     *
     * @param session 可选的参数。session为与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(@PathParam("pageCode") String pageCode, Session session) {
        List<Session> sessions = electricSocketMap.get(pageCode);
        if (null == sessions) {
            List<Session> sessionList = new ArrayList<>();
            sessionList.add(session);
            electricSocketMap.put(pageCode, sessionList);
        } else {
            sessions.add(session);
        }
        try {


            onOpenFind_S_C_MessageToUser(pageCode);


        }catch (Exception e){
            e.printStackTrace();
        }

    }
    /**连接消息中心时查询数据库并返回消息通知
     * 和消息中心的查数量指令
     * */

    public MongoDB_S_C_WebSocketSendMessageEntity onOpenFind_S_C_MessageToUser(String pageCode) throws IOException, EncodeException {
        UserLoginService userLoginService = applicationContext.getBean(UserLoginService.class);
        UserFusionService userFusionService = applicationContext.getBean(UserFusionService.class);
        MessageCenterService messageCenterService = applicationContext.getBean(MessageCenterService.class);
        MongoDB_S_C_SaveDailyContextDao mongoDB_s_c_saveDailyContextDao = applicationContext.getBean(MongoDB_S_C_SaveDailyContextDao.class);
        Spot_Check_FusionService spot_check_fusionService = applicationContext.getBean(Spot_Check_FusionService.class);


        MongoDB_S_C_WebSocketSendMessageEntity mongoDB_s_c_webSocketSendMessageEntity = new MongoDB_S_C_WebSocketSendMessageEntity();


        UserEntity userEntity = userLoginService.findUser(pageCode);
        List<User_RoleEntity> user_roleEntities = userLoginService.uidFindUser_Role(userEntity.getUid());
        List<Permission_TBEntity> permission_tbEntities = new ArrayList<>();
        for (User_RoleEntity user_roleEntity : user_roleEntities) {
            List<Urole_PermissionEntity> urole_permissionEntities = userFusionService.uRidFindURPermission(user_roleEntity.getUroleId());
            for (Urole_PermissionEntity urole_permissionEntity : urole_permissionEntities) {
                Permission_TBEntity permission_tbEntity = userFusionService.permissionIdFindpermission(urole_permissionEntity.getUPPermissionId());
                permission_tbEntities.add(permission_tbEntity);
            }
        }

        Integer groupId = userEntity.getGroupId();
        //用户认证权限的认证  开始
        Collection<MongoDB_S_C_SysAuthAuditMessageEntity> userAuthAuditMessage = null;
        int userManageAuditCount = 0;
        for (Permission_TBEntity permission_tbEntity : permission_tbEntities) {
            if (permission_tbEntity.getPermission().equalsIgnoreCase("u5")) {
                Group_TBEntity group_tbEntity = messageCenterService.groupIdFindGroup(groupId);
                String group = group_tbEntity.getGroupContext();
                userAuthAuditMessage = messageCenterService.findUserAuthAuditMessage(CalculationIsType.calculationIsGroupType(group));
                break;
            }
        }
        if (userAuthAuditMessage != null) {
            userManageAuditCount = userAuthAuditMessage.size();
        }
        //用户认证权限的认证  结束


        //点检添加审核  开始
        int SCAddAuditCount = 0;
        List<MongoDB_S_C_WebSocketMessageEntity> SCAddAudit = null;
        for (Permission_TBEntity permission_tbEntity : permission_tbEntities) {
            if (permission_tbEntity.getPermission().equals("s3")){
                SCAddAudit = spot_check_fusionService.findMongoDB_S_C_WebSocketMessageEntity(permission_tbEntity);
                break;
            }
        }

        if (SCAddAudit != null ){
            SCAddAuditCount = SCAddAudit.size();

        }
        //点检添加审核  结束
        //点检业务审核 开始
        int SCDailyAuditCount =0;
        List<MongoDB_S_C_SaveSCDailyContextEntity> SCDailyAudit = null;

        for (Permission_TBEntity permission_tbEntity : permission_tbEntities) {
            if (permission_tbEntity.getPermission().equals("s4")){
                SCDailyAudit = spot_check_fusionService.findMongoDB_S_C_SaveSCDailyContextEntity(permission_tbEntity);
                break;
            }
        }
        if (SCDailyAudit != null ){
            SCDailyAuditCount = SCDailyAudit.size();
        }

        //点检业务审核 结束

        //点检异常对应消息 开始
        int SCDailyExCount = 0;
        List<MongoDB_S_C_WebSocketMessageEntity> SCDailyEx = null;
        for (Permission_TBEntity permission_tbEntity : permission_tbEntities) {
            if (permission_tbEntity.getPermission().equals("s5")){

                SCDailyEx = spot_check_fusionService.findMongoDB_S_C_WebSocketMessageEntity(permission_tbEntity);
                break;
            }
        }
        if (SCDailyEx != null ){
            SCDailyExCount = SCDailyEx.size();

        }
        //点检异常对应消息 结束

        //通知消息 开始
        int normalMessagesCount = 0;
        List<MongoDB_S_C_WebSocketSendMessageEntity> normalMessages = messageCenterService.findNormalMessages(pageCode);
        for (MongoDB_S_C_WebSocketSendMessageEntity normalMessage : normalMessages) {
            normalMessagesCount++;
        }

        //通知消息 结束

        //我的消息 开始
        int MyMessageCount = 0;
        //我的消息 结束
        //系统消息 开始
        int sysMessageCount = 0;
        List<User_RoleEntity> user_roleEntities2 = userLoginService.uidFindUser_Role(userEntity.getUid());
        List<MongoDB_S_C_WebSocketSendMessageEntity> sysMessages = messageCenterService.findSysMessages(user_roleEntities2);
        for (MongoDB_S_C_WebSocketSendMessageEntity sysMessage : sysMessages) {
            sysMessageCount++;
        }

        //系统消息 结束


        int BusinessMessageCount = SCAddAuditCount + SCDailyAuditCount +SCDailyExCount;
        int totalCount = userManageAuditCount + BusinessMessageCount + normalMessagesCount + sysMessageCount + MyMessageCount;

        mongoDB_s_c_webSocketSendMessageEntity.setLastUname(pageCode);
        mongoDB_s_c_webSocketSendMessageEntity.setMessageCount(totalCount);
        mongoDB_s_c_webSocketSendMessageEntity.setMessage("您有 " +totalCount + " 条信息待处理！");
        GetServerDate.getMessageTime(mongoDB_s_c_webSocketSendMessageEntity);

        mongoDB_s_c_webSocketSendMessageEntity.setUserManageMessageCount(userManageAuditCount);
        mongoDB_s_c_webSocketSendMessageEntity.setBusinessMessageCount(BusinessMessageCount);
        mongoDB_s_c_webSocketSendMessageEntity.setMyMessageCount(MyMessageCount);
        mongoDB_s_c_webSocketSendMessageEntity.setCommonMessageCount(normalMessagesCount);
        mongoDB_s_c_webSocketSendMessageEntity.setSysMessageCount(sysMessageCount);

        if (electricSocketMap.get(pageCode) != null) {
            List<Session> sessions = electricSocketMap.get(pageCode);
            for (Session session : sessions) {

                synchronized (session) {
                    session.getBasicRemote().sendObject(mongoDB_s_c_webSocketSendMessageEntity);
                }
            }

        }
        return mongoDB_s_c_webSocketSendMessageEntity;
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(@PathParam("pageCode") String pageCode, Session session) {
        if (electricSocketMap.containsKey(pageCode)) {
            electricSocketMap.get(pageCode).remove(session);
            System.out.println("链接关闭！");
        }
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("websocket received message:" + message);
        try {
//            session.getBasicRemote().sendText("这是推送测试数据！您刚发送的消息是："+message);
            for (List<Session> s : electricSocketMap.values()) {
                for (Session value : s) {
                    synchronized (session) {
                        value.getBasicRemote().sendText("这是推送测试数据！您刚发送的消息是：" + message);
                    }
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**向指定用户推送消息的方法
     * */
    /*MongoDB_S_C_WebSocketSendMessageEntity messageEntity*/
    public void sendToUser(Object messageEntity1, MessageType messageType) throws IOException, EncodeException {
        //根据类型执行方法
        if (messageEntity1 instanceof MongoDB_S_C_WebSocketSendMessageEntity){
            MongoDB_S_C_WebSocketSendMessageEntity messageEntity = (MongoDB_S_C_WebSocketSendMessageEntity)messageEntity1;
            UserLoginService userLoginService = applicationContext.getBean(UserLoginService.class);
            MessageCenterService messageCenterService = applicationContext.getBean(MessageCenterService.class);
            Spot_Check_FusionService spot_check_fusionService = applicationContext.getBean(Spot_Check_FusionService.class);
            UserFusionService userFusionService = applicationContext.getBean(UserFusionService.class);


                MongoDB_S_C_WebSocketMessageEntity mongoDB_s_c_webSocketMessageEntity;
                List<Permission_TBEntity> permission_tbEntities;

                permission_tbEntities = messageEntity.getMongoDB_s_c_webSocketMessageEntity().getPermission_tbEntities();


                List<Urole_PermissionEntity> urole_permissionEntities1 = new ArrayList<>();
                for (Permission_TBEntity permission_tbEntity : permission_tbEntities) {
                    Integer permissionId = permission_tbEntity.getPermissionId();
                    List<Urole_PermissionEntity> urole_permissionEntities = userFusionService.permissionIdFindURoleId(permissionId);
                    for (Urole_PermissionEntity urole_permissionEntity : urole_permissionEntities) {
                        if (!urole_permissionEntities1.isEmpty()){
                            for (Urole_PermissionEntity urolePermissionEntity : urole_permissionEntities1) {
                                if (!urolePermissionEntity.getUPPermissionId().equals(urole_permissionEntity.getUPPermissionId())){
                                    urole_permissionEntities1.add(urole_permissionEntity);
                                }
                            }
                        }else {
                            urole_permissionEntities1.addAll(urole_permissionEntities);
                        }

                    }

                }
                List<UserEntity> userEntities1 = new ArrayList<>();
                for (Urole_PermissionEntity urole_permissionEntity : urole_permissionEntities1) {
                    Integer upUroleId = urole_permissionEntity.getUPUroleId();
                    List<UserEntity> userEntities = userLoginService.uridFindUserName(upUroleId);
                    if (!userEntities.isEmpty()){
                        for (UserEntity userEntity : userEntities) {
                            for (UserEntity entity : userEntities1) {
                                if (!entity.getUid().equals(userEntity.getUid())){
                                    userEntities1.add(userEntity);
                                }
                            }
                        }
                    }else {
                        userEntities1.addAll(userEntities);
                    }
                }

                messageEntity.setMessageType(messageType);
                messageEntity.setMessage("您有新的" + messageEntity.getMessageType().getValue() + "消息待处理");
                mongoDB_s_c_webSocketMessageEntity = messageEntity.getMongoDB_s_c_webSocketMessageEntity();


                //先存mongodb再通知
                /**重要消息在产生类存储，缩短逻辑链路，避免因为系统问题导致重要消息无法接收
                 * */

                spot_check_fusionService.saveWebSocketMessage_S_C_Audit(mongoDB_s_c_webSocketMessageEntity);
            if (electricSocketMap != null) {
                for (UserEntity userEntity : userEntities1) {
                    if (electricSocketMap.get(userEntity.getUname()) != null) {
                        List<Session> sessions = electricSocketMap.get(userEntity.getUname());
                        for (Session session : sessions) {
                            // TODO: 2023/1/11 线程问题，由于jvm的特性 ->
                            //  尽量不要使用 synchronized(String a) 因为JVM中，字符串常量池具有缓存功能！，就会导致加锁在同一个对象。
                            //  有影响但不大有时间解决！！！业务设计的问题
                            synchronized (session) {
                                session.getBasicRemote().sendObject(messageEntity);
                            }
                        }
                    }

                }
            }
        }
        if (messageEntity1 instanceof MongoDB_S_C_SaveSCDailyContextEntity) {
            MongoDB_S_C_SaveSCDailyContextEntity messageEntity = (MongoDB_S_C_SaveSCDailyContextEntity)messageEntity1;
            UserLoginService userLoginService = applicationContext.getBean(UserLoginService.class);
            MessageCenterService messageCenterService = applicationContext.getBean(MessageCenterService.class);
            Spot_Check_FusionService spot_check_fusionService = applicationContext.getBean(Spot_Check_FusionService.class);
            UserFusionService userFusionService = applicationContext.getBean(UserFusionService.class);

            if (electricSocketMap != null) {
                List<Urole_PermissionEntity> urole_permissionEntities1 = new ArrayList<>();

                for (Permission_TBEntity permission_tbEntity : messageEntity.getPermission_tbEntities()) {
                    int permissionId = permission_tbEntity.getPermissionId();
                    List<Urole_PermissionEntity> urole_permissionEntities = userFusionService.permissionIdFindURoleId(permissionId);
                    for (Urole_PermissionEntity urole_permissionEntity : urole_permissionEntities) {
                        if (!urole_permissionEntities1.isEmpty()){
                            for (Urole_PermissionEntity urolePermissionEntity : urole_permissionEntities1) {
                                if (!urolePermissionEntity.getUPPermissionId().equals(urole_permissionEntity.getUPPermissionId())){
                                    urole_permissionEntities1.add(urole_permissionEntity);
                                }
                            }
                        }else {
                            urole_permissionEntities1.addAll(urole_permissionEntities);
                        }
                    }
                }

                List<UserEntity> userEntities1 = new ArrayList<>();
                for (Urole_PermissionEntity urole_permissionEntity : urole_permissionEntities1) {
                    Integer upUroleId = urole_permissionEntity.getUPUroleId();
                    List<UserEntity> userEntities = userLoginService.uridFindUserName(upUroleId);
                    if (!userEntities.isEmpty()){
                        for (UserEntity userEntity : userEntities) {
                            for (UserEntity entity : userEntities1) {
                                if (!entity.getUid().equals(userEntity.getUid())){
                                    userEntities1.add(userEntity);
                                }
                            }
                        }
                    }else {
                        userEntities1.addAll(userEntities);
                    }
                }
                //先存mongodb再通知
                /**重要消息在产生类存储，缩短逻辑链路，避免因为系统问题导致重要消息无法接收
                 * */



                for (UserEntity userEntity : userEntities1) {
                    if (electricSocketMap.get(userEntity.getUname()) != null) {
                        List<Session> sessions = electricSocketMap.get(userEntity.getUname());
                        for (Session session : sessions) {
                            // TODO: 2023/1/11 线程问题，由于jvm的特性 ->
                            //  尽量不要使用 synchronized(String a) 因为JVM中，字符串常量池具有缓存功能！，就会导致加锁在同一个对象。
                            //  有影响但不大有时间解决！！！业务设计的问题
                            synchronized (session) {
                                session.getBasicRemote().sendObject(messageEntity);
                            }
                        }
                    }

                }
            }
        }

        }




    /**发送个人消息
     * */
    public void SendPrivateMessagesToUser(MongoDB_S_C_WebSocketSendMessageEntity sendMessageEntity, String pageCode){
        try{
                sendMessageEntity.setMessageCount(1);
                if (electricSocketMap.get(pageCode) != null){
                    List<Session> sessions = electricSocketMap.get(pageCode);
                    for (Session session : sessions) {
                        session.getBasicRemote().sendObject(sendMessageEntity);
                    }
                }

        }catch (IOException | EncodeException exception) {
            exception.printStackTrace();
        }

    }

    /**给系统管理员发消息
     * */


    /**
     * 发生错误时调用
     *
     */
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("发生错误");

    }
}